package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.tanhua.autoconfig.template.HuanXinTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.CommentApi;
import com.tanhua.dubbo.api.QuestionApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.mongo.RecommendUserApi;
import com.tanhua.dubbo.mongo.UserLikeApi;
import com.tanhua.dubbo.mongo.UserLocationApi;
import com.tanhua.dubbo.mongo.VisitorsApi;
import com.tanhua.model.domain.Question;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.dto.RecommendUserDto;
import com.tanhua.model.mongo.RecommendUser;
import com.tanhua.model.mongo.UserLike;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.*;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.exception.ErrorResult;
import com.tanhua.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TanhuaService {
    @Autowired
    private MessagesService messagesService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private HuanXinTemplate huanXinTemplate;
    @DubboReference
    private UserLocationApi userLocationApi;
    @DubboReference
    private RecommendUserApi recommendUserApi;
    @DubboReference
    private UserInfoApi userInfoApi;
    @DubboReference
    private QuestionApi questionApi;
    @DubboReference
    private UserLikeApi userLikeApi;
    @DubboReference
    private VisitorsApi visitorsApi;
    @DubboReference
    private CommentApi commentApi;

    @Value("${tanhua.default.recommend.users}")
    private String recommendUser;

    /**
     * 每日置顶佳人
     *
     * @return 佳人详情
     */
    public TodayBest todayBest() {
        //1、获取用户id
//        Long userId = UserHolder.getUserId();
        //2、调用API查询
        RecommendUser recommendUser = recommendUserApi
                .queryWithMaxScore(UserHolder.getUserId());
        log.info("=================={}", recommendUser.toString());
        if (recommendUser == null) {
            //当未查询到今日佳人，设置默认对象
            recommendUser = new RecommendUser();
            recommendUser.setUserId(1l);
            recommendUser.setScore(99d);
        }
        //3、将RecommendUser转化为TodayBest对象
        UserInfo byId = userInfoApi.findById(recommendUser.getUserId());
        log.info("=================================用户详细信息：{}", byId);
        TodayBest vo = TodayBest.init(byId, recommendUser);

        //4、返回
        return vo;
    }

    /**
     * 查询页面推荐用户
     *
     * @param dto 条件
     * @return 根据条件筛选出的用户详细信息
     */
    public PageResult recommendation(RecommendUserDto dto) {
        //1、获取用户id
        Long userId = UserHolder.getUserId();
        //2、调用recommendUserApi分页查询数据列表（PageResult -- RecommendUser）
        PageResult result = recommendUserApi
                .queryRecommendUserList(dto.getPage(),
                        dto.getPagesize(),
                        userId);
        //3、获取分页中的RecommendUser数据列表
        List<RecommendUser> items = (List<RecommendUser>) result.getItems();
        //4、判断列表是否为空
        if (items == null || items.size() <= 0) {
            return result;
        }
        //5、提取所有推荐的用户id列表
        List<Long> userIds = items
                .stream().map(item -> item.getUserId())
                .collect(Collectors.toList());
        UserInfo userInfo = new UserInfo();
        //用户设置的年龄和性别
        userInfo.setAge(dto.getAge());
        userInfo.setGender(dto.getGender());
        //6、构建查询条件，批量查询所有的用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, userInfo);
        log.info(map + "-------------------------");
        //7、循环推荐的数据列表，构建vo对象
        List<TodayBest> list = new ArrayList<>();
        for (RecommendUser item : items) {
            //获取map中的每个用户详细信息
            UserInfo userInFo = map.get(item.getUserId());
            if (userInFo != null) {
                list.add(TodayBest.init(userInFo, item));
            }
        }
        log.info(list.toString());
        //8、构造返回值
        result.setItems(list);
        log.info(result.toString());
        return result;
    }

    /**
     * 查看佳人详情
     *
     * @param userId 佳人id
     * @return 佳人详情
     */
    public TodayBest personalInfo(Long userId) {

        //1、根据用户id查询，用户详情
        UserInfo userInfo = userInfoApi.findById(userId);
        //2、根据操作人id和查看的用户id，查询两者的推荐数据
        RecommendUser user = recommendUserApi.queryByUserId(userId, UserHolder.getUserId());
        //保存访客记录,封装访客信息
        Visitors visitors = new Visitors();
        //设置被查看人id
        visitors.setUserId(userId);
        //设置查看人id
        visitors.setVisitorUserId(UserHolder.getUserId());
        //设置为首页
        visitors.setFrom("首页");
        //设置来访时间
        visitors.setDate(System.currentTimeMillis());
        //设置来访日期
        visitors.setVisitDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        //设置得分
        visitors.setScore(user.getScore());
        //调用方法保存访客记录
        visitorsApi.save(visitors);

        //3、构造返回值
        return TodayBest.init(userInfo, user);

    }

    /**
     * 查询陌生人问题
     *
     * @param userId 陌生人id
     * @return 陌生人问题
     */
    public String strangerQuestions(Long userId) {
        //根据id查询陌生人详情
        Question byUserId = questionApi.findByUserId(userId);
        //返回问题
        String question = byUserId == null ? "你喜欢java吗？" : byUserId.getTxt();
        return question;
    }

    /**
     * 回复陌生人问题
     *
     * @param userId 陌生人id
     * @param reply  回复内容
     */
    public void replyQuestions(Long userId, String reply) {
        //1、构造消息数据
        Long id = UserHolder.getUserId();
        //获取发送人信息
        UserInfo userInfo = userInfoApi.findById(id);

        //封装回复信息
        Map map = new HashMap();
        map.put("userId", id);
        map.put("nickname", userInfo.getNickname());
        //获取陌生人问题
        map.put("strangerQuestion", strangerQuestions(userId));
        map.put("reply", reply);
        //map转json
        String s = JSON.toJSONString(map);
        //调用template对象，发送消息
        Boolean aBoolean = huanXinTemplate.sendMsg(Constants.HX_USER_PREFIX + userId, s);
        if (!aBoolean) {
            throw new BusinessException(ErrorResult.error());
        }
    }

    /**
     * 左滑右滑展示界面
     *
     * @return
     */
    public List<TodayBest> cards() {
        //根据当前用户查询
        List<RecommendUser> recommendUsers = recommendUserApi.queryCardsList(UserHolder.getUserId(), 10);
        if (CollUtil.isEmpty(recommendUsers)) {
            String[] split = recommendUser.split(",");
            recommendUsers = Arrays.stream(split).map((item) -> {
                RecommendUser recommendUser = new RecommendUser();
                recommendUser.setUserId(Convert.toLong(item));
                recommendUser.setToUserId(UserHolder.getUserId());
                recommendUser.setScore(RandomUtil.randomDouble(60, 90));
                return recommendUser;
            }).collect(Collectors.toList());
        }
        List<Long> collect = recommendUsers.stream().map(item -> item.getUserId()).collect(Collectors.toList());
        Map<Long, UserInfo> map = userInfoApi.findByIds(collect, null);

        List<TodayBest> vos = new ArrayList<>();
        for (RecommendUser user : recommendUsers) {
            UserInfo userInfo = map.get(user.getUserId());
            if (userInfo != null) {
                TodayBest vo = TodayBest.init(userInfo, user);
                vos.add(vo);
            }
        }
        return vos;
    }

    /**
     * 不喜欢
     *
     * @param likeUserId
     */
    public void unlove(String likeUserId) {
        Boolean aBoolean = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, false);
        if (!aBoolean) {
            //没有保存成功，抛出异常
            throw new BusinessException(ErrorResult.error());
        }
        //2、操作redis，写入喜欢的数据，删除不喜欢的数据 (喜欢的集合，不喜欢的集合)
        redisTemplate.opsForSet().add(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        redisTemplate.opsForSet().remove(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        //3、判断是否双向喜欢，删除好友(各位自行实现)
    }

    /**
     * 喜欢
     *
     * @param likeUserId
     */
    public void lave(String likeUserId) {
        Boolean aBoolean = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, true);
        if (!aBoolean) {
            //没有保存成功，抛出异常
            throw new BusinessException(ErrorResult.error());
        }
        //将喜欢的数据保存到redis中
        redisTemplate.opsForSet().remove(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        redisTemplate.expire(Constants.USER_LIKE_KEY + UserHolder.getUserId(), 60l, TimeUnit.MINUTES);
        //3、判断是否双向喜欢
        if (isLike(Long.valueOf(likeUserId), UserHolder.getUserId())) {
            //4、添加好友
            messagesService.contacts(Long.valueOf(likeUserId));
        }
    }

    /**
     * 不喜欢
     *
     * @param likeUserId
     * @param userId
     * @return
     */
    private boolean isLike(Long likeUserId, Long userId) {
        String key = Constants.USER_LIKE_KEY + likeUserId;
        Boolean member = redisTemplate.opsForSet().isMember(userId.toString(), key);
        if (member) {
            return true;
        }
        return false;
    }

    /**
     * 搜附近
     *
     * @param gender
     * @param distance
     * @return
     */
    public List<NearUserVo> queryNearUser(String gender, String distance) {
        //1、调用API查询附近的用户（返回的是附近的人的所有用户id，包含当前用户的id）
        List<Long> userIds = userLocationApi.queryNearUser(UserHolder.getUserId(), Double.valueOf(distance));
        //2、判断集合是否为空
        if (CollUtil.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        //3、调用UserInfoApi根据用户id查询用户详情
        UserInfo userInfo = new UserInfo();
        userInfo.setGender(gender);
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, userInfo);
        //4、构造返回值。
        List<NearUserVo> vos = new ArrayList<>();
        for (Long userId : userIds) {
            //排除当前用户
            if (userId == UserHolder.getUserId()) {
                continue;
            }
            UserInfo info = map.get(userId);
            if (info != null) {
                NearUserVo vo = NearUserVo.init(info);
                vos.add(vo);
            }
        }
        return vos;
    }

    /**
     * 是否喜欢
     *
     * @param id
     * @return
     */
    public Boolean alreadyLove(Long id) {
        Boolean b = commentApi.findByUserIdAndPublishUserId(UserHolder.getUserId(), id);
        return b;
    }

    /**
     * 统计次数
     *
     * @return
     */
    public Map counts() {
        //查询喜欢
        Integer loveCount = userLikeApi.loveCounts(UserHolder.getUserId()).size();
        //查询粉丝
        Integer fanCount = userLikeApi.fanCounts(UserHolder.getUserId()).size();
        //查询互相喜欢
        Integer eachLoveCount = userLikeApi.eachLoveCounts(UserHolder.getUserId()).size();
        Map map = new HashMap();
        map.put("loveCount", loveCount);
        map.put("fanCount", fanCount);
        map.put("eachLoveCount", eachLoveCount);
        return map;
    }

    /**
     * 1 互相关注
     * 2 我关注
     * 3 粉丝
     * 4 谁看过我
     *
     * @param type
     * @param page
     * @param pagesize
     * @param nickname
     * @return
     */
    public PageResult friends(Integer type, Integer page, Integer pagesize, String nickname) {
        PageResult pageResult = new PageResult(page, pagesize, 0, null);
        switch (type) {
            case 1:
                List<FriendsVo> eachLoves = eachLove(page, pagesize);
                log.info(eachLoves.toString());
                pageResult.setItems(eachLoves);
                break;
            case 2:
                List<FriendsVo> loves = love(page, pagesize);
                pageResult.setItems(loves);
                break;
            case 3:
                List<FriendsVo> fans = fan(page, pagesize);
                pageResult.setItems(fans);
                break;
            case 4:
                List<FriendsVo> visitorss = visitors(page, pagesize);
                log.info("谁看过我列表---------{}", visitorss.toString());
                pageResult.setItems(visitorss);
                break;
            default:
                throw new BusinessException(ErrorResult.error());
        }
        log.info("查询出的列表数据{}", pageResult.getItems().toString());
        String s = JSON.toJSONString(pageResult);
        log.info(s);
        return pageResult;
    }

    //谁看过我
    private List<FriendsVo> visitors(Integer page, Integer pagesize) {
        List<Visitors> v = visitorsApi.find(UserHolder.getUserId(), page, pagesize);
        Set<Long> collect = v.stream().map(item -> item.getVisitorUserId()).collect(Collectors.toSet());
        Map<Long, Double> map = new HashMap<>();
        for (Visitors visitors : v) {
            map.put(visitors.getVisitorUserId(), visitors.getScore());
        }
        List<FriendsVo> list = new ArrayList<>();
        for (Long aLong : collect) {
            UserInfo byId = userInfoApi.findById(aLong);
            boolean b = userLikeApi.findByIdAndLikeId(UserHolder.getUserId(), aLong);
            FriendsVo friendsVo = FriendsVo.init(byId);
            //查询分数
            RecommendUser recommendUser = recommendUserApi.queryByUserId(UserHolder.getUserId(), aLong);
            if (recommendUser != null) {
                String s = recommendUser.getScore().toString().split("\\.")[0];
                friendsVo.setMatchRate(Integer.valueOf(s));
            }
            friendsVo.setAlreadyLove(b);
        }
        return list;
    }

    //粉丝
    private List<FriendsVo> fan(Integer page, Integer pagesize) {
        List<UserLike> list = userLikeApi.fan(UserHolder.getUserId(), page, pagesize);
        return getUserInfoVos(list);

    }

    private List<FriendsVo> getUserInfoVos(List<UserLike> list) {
        List<Long> collect = list.stream().map(item -> item.getLikeUserId()).collect(Collectors.toList());
        Map<Long, UserInfo> byIds = userInfoApi.findByIds(collect, null);
        List<FriendsVo> friendsVos = new ArrayList<>();
        for (Long aLong : collect) {
            UserInfo userInfo = byIds.get(aLong);
            FriendsVo init = FriendsVo.init(userInfo);
            boolean byIdAndLikeId = userLikeApi.findByIdAndLikeId(UserHolder.getUserId(), aLong);
            init.setAlreadyLove(byIdAndLikeId);
            RecommendUser recommendUser = recommendUserApi.queryByUserId(UserHolder.getUserId(), aLong);
            if (recommendUser != null) {
                String s = recommendUser.getScore().toString().split("\\.")[0];
                init.setMatchRate(Integer.valueOf(s));
            }
            friendsVos.add(init);
        }
        return friendsVos;
    }

    //喜欢
    private List<FriendsVo> love(Integer page, Integer pagesize) {
        List<UserLike> list = userLikeApi.love(UserHolder.getUserId(), page, pagesize);
        return getUserInfoVos(list);
    }

    //互相喜欢
    private List<FriendsVo> eachLove(Integer page, Integer pagesize) {
        List<UserLike> list = userLikeApi.eachLove(UserHolder.getUserId(), page, pagesize);

        return getUserInfoVos(list);
    }

}
